"""
### 根据前15日 的信息预测未来一日的多空,

数据量太少，过拟合很严重,



"""
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import tensorflow as tf
from tensorflow import keras

csv_path = "/Users/aloudata/Downloads/train_data/M999/M9999-DAY-format1.XDCE.csv"

df = pd.read_csv(csv_path)

target = df[["target"]]
features = df.iloc[:, :15]


def split_features(features):
    new_features = []
    for f in features:
        f_map = map(lambda x: list(map(float, x.split(":"))), f)
        new_features.append(list(f_map))
    return new_features


"""
### 数据归一化

    


"""


def normalize(data):
    new_features = []
    for f in data:
        ptp = f[:, :4].ptp()
        volume_ptp = f[:, 4:5].ptp()
        money_ptp = f[:, 5:6].ptp()
        position_ptp = f[:, 6:7].ptp()
        # new_features.append((f - means) / std)
        ptp = [ptp, ptp, ptp, ptp, volume_ptp, money_ptp, position_ptp]
        new_features.append((f - f[0]) / ptp)
    return np.array(new_features)


print("Total Feature shape", features.values.shape)
print("Total Target shape", target.values.shape)

"""
## Training
"""
split_fraction = 0.80
train_split = int(split_fraction * int(features.shape[0]))

features = pd.DataFrame(features)
features.head()

train_data = features.loc[0: train_split - 1]
train_data = normalize(np.array(split_features(train_data.values)))
train_target = target.loc[0: train_split - 1]
print("Train Feature shape", train_data.shape)
print("Train Target shape", train_target.shape)

val_data = features.loc[train_split:]
val_feature = np.array(split_features(val_data.values))
val_data = normalize(val_feature)
val_target = target.loc[train_split:]
print("Val Feature shape", val_data.shape)
print("Val Target shape", val_target.shape)

learning_rate = 0.001
epochs = 200

model = keras.Sequential()
model.add(keras.layers.Input(shape=(train_data.shape[1], train_data.shape[2])))
model.add(keras.layers.LSTM(units=64, activation=keras.activations.sigmoid,
                            kernel_initializer=keras.initializers.glorot_normal,
                            dropout=0.02,
                            return_sequences=True))
model.add(keras.layers.LayerNormalization())
model.add(keras.layers.LSTM(units=32, activation=keras.activations.sigmoid,
                            kernel_initializer=keras.initializers.glorot_normal))
model.add(keras.layers.Dense(units=128,
                             activation=keras.activations.sigmoid,
                             kernel_initializer=keras.initializers.glorot_normal))
model.add(keras.layers.Dropout(0.02))
model.add(keras.layers.Dense(units=64,
                             activation=keras.activations.sigmoid,
                             kernel_initializer=keras.initializers.glorot_normal))
model.add(keras.layers.LayerNormalization())
# model.add(keras.layers.Dropout(0.2))
model.add(keras.layers.Dense(units=1, activation=keras.activations.sigmoid))
model.compile(optimizer=keras.optimizers.Adam(learning_rate=learning_rate, weight_decay=0.01),
              loss=keras.losses.binary_crossentropy, metrics=["accuracy"])

model.summary()

model_path = "./model/model_day_decision_m999.h5"
es_callback = keras.callbacks.EarlyStopping(monitor="val_loss", min_delta=0, patience=5)

modelckpt_callback = keras.callbacks.ModelCheckpoint(
    monitor="val_loss",
    filepath=model_path,
    verbose=1,
    save_weights_only=True,
    save_best_only=True,
)

history = model.fit(
    train_data,
    train_target,
    batch_size=1024,
    epochs=epochs,
    verbose=2,
    callbacks=[],
    validation_data=(val_data, val_target),
)


def visualize_loss(history, title):
    loss = history.history["loss"]
    val_loss = history.history["val_loss"]
    epochs = range(len(loss))
    plt.figure()
    plt.plot(epochs, loss, "b", label="Training loss")
    plt.plot(epochs, val_loss, "r", label="Validation loss")
    plt.title(title)
    plt.xlabel("Epochs")
    plt.ylabel("Loss")
    plt.legend()
    plt.show()


model.save(model_path)

def is_predict_right(expect, predict_val):
    return expect == round(predict_val)


def draw_predict_figure(close, val_target, predict_target):
    x_len = len(val_target)
    x_plot = range(x_len)
    plt.figure()
    marker = [".-", "rx", "go"]
    error = [0] * x_len
    right = [0] * x_len
    for i in x_plot:
        if is_predict_right(val_target[i], predict_target[i]):
            right[i] = close[i]
        else:
            error[i] = close[i]
    plt.plot(x_plot, close, ".-", label="Price")
    plt.plot(x_plot, error, "rx", label="Real")
    plt.plot(x_plot, right, "go", label="Predict")
    plt.title("Predict Target")
    plt.xlabel("Epochs")
    plt.ylabel("Loss")
    plt.legend()
    plt.show()


visualize_loss(history, "Training and Validation Loss")

tr, accuracy = model.evaluate(val_data, val_target)
print(f"Test tr: {tr}%")
print(f"Test accuracy: {round(accuracy * 100, 2)}%")
predict = model.predict(val_data)

print(predict)
draw_predict_figure(val_feature[:, 14:, 3:4].flatten(), np.array(val_target.values).flatten(),
                    np.array(predict).flatten())



